package com.gitee.qdbp.general.system.biz.personnel.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.ordering.OrderPaging;
import com.gitee.qdbp.able.jdbc.paging.PageList;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.base.controlling.IDataIsolationControlling;
import com.gitee.qdbp.base.enums.Gender;
import com.gitee.qdbp.base.enums.OperateType;
import com.gitee.qdbp.base.system.model.IAccountType;
import com.gitee.qdbp.base.system.service.IPasswordService;
import com.gitee.qdbp.general.common.api.sequence.service.ILocalSequenceGenerator;
import com.gitee.qdbp.general.system.api.personnel.basic.IUserCoreBasic;
import com.gitee.qdbp.general.system.api.personnel.convert.IUserSourceConverter;
import com.gitee.qdbp.general.system.api.personnel.model.AccountBean;
import com.gitee.qdbp.general.system.api.personnel.model.UserCoreBean;
import com.gitee.qdbp.general.system.api.personnel.model.UserCoreUpdate;
import com.gitee.qdbp.general.system.api.personnel.model.UserCoreWhere;
import com.gitee.qdbp.general.system.api.personnel.service.IUserAuthExecutor;
import com.gitee.qdbp.general.system.biz.personnel.service.impl.EmailValidCodeService;
import com.gitee.qdbp.general.system.biz.personnel.service.impl.SmsValidCodeService;
import com.gitee.qdbp.general.system.enums.UserState;
import com.gitee.qdbp.general.system.error.UserErrorCode;
import com.gitee.qdbp.tools.utils.JsonTools;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 管理员认证授权实现类
 *
 * @author zhaohuihua
 * @version 151010
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class UserAuthExecutor implements IUserAuthExecutor {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(UserAuthExecutor.class);

    @Autowired
    private UserCoreExecutor userCoreExecutor;
    @Autowired
    private IUserCoreBasic userCoreBasic;
    @Autowired
    private SmsValidCodeService smsValidCodeService;
    @Autowired
    private EmailValidCodeService emailValidCodeService;
    @Autowired
    private IPasswordService passwordService;
    @Autowired
    private IUserSourceConverter userSourceConverter;
    @Autowired
    private ILocalSequenceGenerator sequenceGenerator;
    @Autowired
    private IDataIsolationControlling dataIsolationControlling;

    @Override
    public UserCoreBean login(String id, String password) throws ServiceException {

        String msg = "Failed to login. ";
        if (VerifyTools.isBlank(id)) {
            log.error(msg + "params is null: id");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(password)) {
            log.error(msg + "params is null: password");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 查找用户
        UserCoreWhere where = new UserCoreWhere();
        where.setId(id);
        UserCoreBean user = findUser(where, password, msg);

        // 判断用户状态
        checkUserState(user);

        user.setPassword(null); // 清空密码
        return user;
    }

    @Override
    public UserCoreBean login(AccountBean model, String password, IAccountType... choose) throws ServiceException {
        String msg = "Failed to login. ";
        if (VerifyTools.isBlank(model.getAccount())) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(password)) {
            log.error(msg + "params is null: password");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        return findActivityUser(model, password, choose);
        // 有些场景需要具体提示, 因此这里不再控制, 改由登录入口控制
        // try {
        //     return findActivityUser(model, password, choose);
        // } catch (ServiceException e) {
        //     //  为防止不断尝试来恶意套取用户名, 不返回用户不存在, 只返回用户名或密码错误
        //     if (e.getCode().equals(UserErrorCode.USER_LOGIN_PASSWORD_ERROR.getCode())) {
        //         throw new ServiceException(UserErrorCode.USER_OR_PASSWORD_ERROR);
        //     } else if (e.getCode().equals(UserErrorCode.USER_NOT_EXIST.getCode())) {
        //         throw new ServiceException(UserErrorCode.USER_OR_PASSWORD_ERROR);
        //     } else {
        //         throw e;
        //     }
        // }
    }

    @Override
    public UserCoreBean findActivityUser(AccountBean model, IAccountType... choose) throws ServiceException {
        return findActivityUser(model, null, choose);
    }

    private UserCoreBean findActivityUser(AccountBean model, String password, IAccountType... choose)
            throws ServiceException {
        String msg = "Failed to find activity user. ";
        if (VerifyTools.isBlank(model.getAccount())) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model.getType())) {
            log.error(msg + "params is null: AccountType");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 合并model中的AccountType和choose
        List<IAccountType> types = concatAccountType(model.getType(), choose);

        // 查找用户
        UserCoreWhere where = toUserCoreWhere(model);
        UserCoreBean user;
        if (types.size() == 0) {
            user = findUser(where, password, msg);
        } else if (types.size() == 1) {
            where.setUserType(types.get(0));
            user = findUser(where, password, msg);
        } else {
            where.setUserTypes(types);
            user = chooseUser(where, password, msg);
        }

        // 判断用户状态
        checkUserState(user);

        user.setPassword(null); // 清空密码
        return user;
    }

    private UserCoreBean findUser(UserCoreWhere where, String password, String msg) throws ServiceException {

        UserCoreBean user;
        try {
            user = userCoreBasic.find(where);
        } catch (Exception e) {
            log.error(msg + "{}. {}", e.toString(), JsonTools.toJsonString(where));
            throw new ServiceException(UserErrorCode.USERINFO_LOGIN_ERROR, e);
        }

        if (user == null) {
            log.warn(msg + "{}. {}", "user not found", JsonTools.toJsonString(where));
            throw new ServiceException(UserErrorCode.USER_NOT_EXIST);
        }

        // 判断密码是否匹配
        if (VerifyTools.isBlank(password) || passwordService.validate(user.getId(), password, user.getPassword())) {
            return user;
        } else { // 密码不匹配
            log.warn(msg + "{}. {}", "password error", JsonTools.toJsonString(where));
            throw new ServiceException(UserErrorCode.USER_LOGIN_PASSWORD_ERROR);
        }
    }

    private UserCoreBean chooseUser(UserCoreWhere where, String password, String msg) throws ServiceException {

        // 根据账号查询所有类型的用户
        PageList<UserCoreBean> all;
        try {
            all = userCoreBasic.list(where, OrderPaging.NONE);
        } catch (Exception e) {
            log.error(msg + "{}. {}", e.toString(), JsonTools.toJsonString(where));
            throw new ServiceException(UserErrorCode.USERINFO_LOGIN_ERROR, e);
        }

        if (all.isEmpty()) {
            log.warn(msg + "{}. {}", "user not found", JsonTools.toJsonString(where));
            throw new ServiceException(UserErrorCode.USER_NOT_EXIST);
        }

        UserCoreBean user = null;
        for (IAccountType tp : where.getUserTypes()) { // 根据账号类型查找密码匹配的账号, 如果没有密码则返回第1个账号
            UserCoreBean u = null;
            for (UserCoreBean bean : all) {
                if (bean.getUserType() == tp) {
                    u = bean;
                    break;
                }
            }
            if (u == null) continue;

            if (VerifyTools.isBlank(password)) {
                user = u;
                break;
            } else { // 判断密码是否匹配
                if (passwordService.validate(u.getId(), password, u.getPassword())) {
                    user = u;
                    break;
                } else { // 密码不匹配
                    log.warn(msg + "type={}, {}. {}", tp, "password error", JsonTools.toJsonString(where));
                    continue;
                }
            }
        }

        if (user != null) {
            return user;
        } else {
            log.warn(msg + "{}. {}", "password error", JsonTools.toJsonString(where));
            throw new ServiceException(UserErrorCode.USER_LOGIN_PASSWORD_ERROR);
        }
    }

    private UserCoreWhere toUserCoreWhere(AccountBean model) {
        String tenantCode = model.getFactory();
        String account = model.getAccount();
        UserCoreWhere where = new UserCoreWhere();
        where.setTenantCode(tenantCode);

        // 根据登录账号的格式判断以哪种类型登录
        if (StringTools.isPhone(account)) {
            where.setPhone(account); // 手机
        } else if (StringTools.isEmail(account)) {
            where.setEmail(account); // 邮箱
        } else {
            where.setUserCode(account); // 登录账号/工号
        }
        return where;
    }

    private List<IAccountType> concatAccountType(IAccountType type, IAccountType[] choose) {
        Set<IAccountType> temp = new TreeSet<>();
        if (type != null) {
            temp.add(type);
        }
        if (choose != null) {
            for (IAccountType tp : choose) {
                if (tp != null) {
                    temp.add(tp);
                }
            }
        }
        return new ArrayList<>(temp);
    }

    private void checkUserState(UserCoreBean user) throws ServiceException {
        // 判断用户状态
        if (user.getUserState() == UserState.NORMAL) {
            // 只允许正常状态的用户登录
        } else if (user.getUserState() == UserState.LOCKED) {
            throw new ServiceException(UserErrorCode.USER_IS_LOCK);
        } else if (user.getUserState() == UserState.UNACTIVATED) {
            throw new ServiceException(UserErrorCode.USER_IS_WAIT_ACTIVITY);
        } else if (user.getUserState() == UserState.LOGOFF) { // 当作用户不存在处理
            throw new ServiceException(UserErrorCode.USER_OR_PASSWORD_ERROR);
        } else { // 未来新增加的状态
            throw new ServiceException(UserErrorCode.USER_STATE_ERROR);
        }
    }

    @Override
    public void checkPassword(String userId, String password) throws ServiceException {
        String msg = "Failed to check password. ";
        if (VerifyTools.isBlank(userId)) {
            log.error(msg + "params is null: userId");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(password)) {
            log.error(msg + "params is null: password");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        UserCoreBean user = userCoreBasic.findById(userId);
        if (user == null) {
            log.error(msg + "user info not found. id:{}", userId);
            throw new ServiceException(UserErrorCode.USER_NOT_EXIST);
        }

        // 验证密码是否正确
        if (!passwordService.validate(userId, password, user.getPassword())) {
            log.error(msg + "old password error. id:{}", userId);
            throw new ServiceException(UserErrorCode.USER_LOGIN_PASSWORD_ERROR);
        }
    }

    @Override
    public void updatePassword(AccountBean model, String newPassword) throws ServiceException {
        String msg = "Failed to update password. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (!StringTools.isPhone(account) && !StringTools.isEmail(account)) {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(newPassword)) {
            log.error(msg + "params is null: newPassword");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        UserCoreBean user = findActivityUser(model);

        doUpdatePassword(model.getFactory(), model.getType(), user.getId(), newPassword);
    }

    @Override
    public void updatePassword(String userId, String oldPassword, String newPassword) throws ServiceException {
        String msg = "Failed to update password. ";
        if (VerifyTools.isBlank(userId)) {
            log.error(msg + "params is null: userId");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(oldPassword)) {
            log.error(msg + "params is null: oldPassword");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(newPassword)) {
            log.error(msg + "params is null: newPassword");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        UserCoreBean user = userCoreBasic.findById(userId);
        if (user == null) {
            log.error(msg + "user info not found. id:{}", userId);
            throw new ServiceException(UserErrorCode.USER_NOT_EXIST);
        }

        // 验证旧密码是否正确
        if (!passwordService.validate(userId, oldPassword, user.getPassword())) {
            log.error(msg + "old password error. id:{}", userId);
            throw new ServiceException(UserErrorCode.OLD_PASSWORD_ERROR);
        }

        doUpdatePassword(user.getTenantCode(), user.getUserType(), userId, newPassword);
    }

    @Override
    public UserCoreBean sendLoginValidCode(AccountBean model, IAccountType... choose) throws ServiceException {
        String msg = "Failed to SendLoginValidCode. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        UserCoreBean uesr = findActivityUser(model, choose);

        if (StringTools.isPhone(account)) {
            smsValidCodeService.sendLoginValidCode(account);
        } else if (StringTools.isEmail(account)) {
            emailValidCodeService.sendLoginValidCode(account);
        } else {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }

        return uesr;
    }

    @Override
    public void checkLoginValidCode(AccountBean model, String validCode, boolean remove) throws ServiceException {
        String msg = "Failed to CheckLoginValidCode. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(validCode)) {
            log.error(msg + "params is null: validCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (StringTools.isPhone(account)) {
            smsValidCodeService.checkLoginValidCode(account, validCode, remove);
        } else if (StringTools.isEmail(account)) {
            emailValidCodeService.checkLoginValidCode(account, validCode, remove);
        } else {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }

    }

    @Override
    public void sendRegisterValidCode(AccountBean model) throws ServiceException {
        String msg = "Failed to SendRegisterValidCode. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 检查手机号码是否已经注册
        userCoreExecutor.checkPhoneThrowOnAlreadyExists(model, null);
        if (StringTools.isPhone(account)) {
            smsValidCodeService.sendRegisterValidCode(account);
        } else if (StringTools.isEmail(account)) {
            emailValidCodeService.sendRegisterValidCode(account);
        } else {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }
    }

    @Override
    public void checkRegisterValidCode(AccountBean model, String validCode) throws ServiceException {
        String msg = "Failed to CheckRegisterValidCode. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(validCode)) {
            log.error(msg + "params is null: validCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (StringTools.isPhone(account)) {
            smsValidCodeService.checkRegisterValidCode(account, validCode, false);
        } else if (StringTools.isEmail(account)) {
            emailValidCodeService.checkRegisterValidCode(account, validCode, false);
        } else {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }
    }

    @Override
    public UserCoreBean registerByValidCode(UserCoreBean model, String validCode) throws ServiceException {
        String msg = "Failed to create User. ";

        // 必填校验
        if (VerifyTools.isBlank(validCode)) {
            log.error(msg + "params is null: validCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model)) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        // 由于保存用户头像图片需要用到tenantCode, 因此需要先处理数据隔离
        dataIsolationControlling.handle(model, OperateType.CREATE, "tenantCode");
        String tenantCode = model.getTenantCode();
        IAccountType userType = model.getUserType();
        String password = model.getPassword();
        if (VerifyTools.isBlank(password)) {
            log.error(msg + "params is null: password");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        String phone = model.getPhone();
        String email = model.getEmail();

        if (VerifyTools.isNotBlank(phone)) {
            model.setEmail(null); // 按手机号码注册时不允许填邮箱地址
            if (!StringTools.isPhone(phone)) { // 检查手机号码格式
                log.error(msg + "params format error: phone=" + phone);
                throw new ServiceException(ResultCode.PARAMETER_FORMAT_ERROR);
            }

            // 检查短信验证码是否正确
            smsValidCodeService.checkRegisterValidCode(phone, validCode, true);

            // 检查手机号码是否已经注册
            AccountBean bean = new AccountBean(tenantCode, userType, phone);
            userCoreExecutor.checkPhoneThrowOnAlreadyExists(bean, null);
        } else if (VerifyTools.isNotBlank(email)) {
            model.setPhone(null); // 按邮箱地址注册时不允许填手机号码
            if (!StringTools.isEmail(email)) { // 检查邮箱地址格式
                log.error(msg + "params format error: email=" + email);
                throw new ServiceException(ResultCode.PARAMETER_FORMAT_ERROR);
            }

            // 检查邮件验证码是否正确
            emailValidCodeService.checkRegisterValidCode(email, validCode, true);

            // 检查邮箱地址是否已经注册
            AccountBean bean = new AccountBean(tenantCode, userType, email);
            userCoreExecutor.checkEmailThrowOnAlreadyExists(bean, null);
        } else {
            log.error(msg + "params is null: phone and email");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        String userId = sequenceGenerator.generate(UserCoreBean.TABLE);
        model.setId(userId); // 生成新的ID
        // 注册时间设置为空, 采用数据库时间
        model.setCreateTime(null);
        if (model.getGender() == null) {
            model.setGender(Gender.UNKNOWN);
        }
        if (model.getUserSource() == null) {
            model.setUserSource(userSourceConverter.getDefaults());
        }
        // 密码加密
        model.setPassword(passwordService.create(userId, password));
        // 将文件从临时路径复制到正式路径
        if (VerifyTools.isNotBlank(model.getPhoto())) {
            model.setPhoto(userCoreExecutor.copyRegisterFileToFormalFolder(model.getPhoto(), tenantCode, userId));
        }

        // 向sys_user_info表插入记录
        userCoreBasic.create(model);

        return model;
    }

    @Override
    public UserCoreBean sendRepasswordValidCode(AccountBean model, IAccountType... choose) throws ServiceException {
        String msg = "Failed to SendRepasswordValidCode. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 检查用户是否存在
        UserCoreBean user = findActivityUser(model, choose);

        if (StringTools.isPhone(account)) {
            smsValidCodeService.sendRepasswordValidCode(account);
        } else if (StringTools.isEmail(account)) {
            emailValidCodeService.sendRepasswordValidCode(account);
        } else {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }

        return user;
    }

    @Override
    public void checkRepasswordValidCode(AccountBean model, String validCode, boolean remove) throws ServiceException {
        String msg = "Failed to CheckRepasswordValidCode. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(validCode)) {
            log.error(msg + "params is null: validCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (StringTools.isPhone(account)) {
            smsValidCodeService.checkRepasswordValidCode(account, validCode, false);
        } else if (StringTools.isEmail(account)) {
            emailValidCodeService.checkRepasswordValidCode(account, validCode, false);
        } else {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }
    }

    @Override
    public void repasswordByValidCode(AccountBean model, String validCode, String newPassword) throws ServiceException {
        String msg = "Failed to RepasswordByPhone. ";
        String account = model.getAccount();
        if (VerifyTools.isBlank(account)) {
            log.error(msg + "params is null: account");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(validCode)) {
            log.error(msg + "params is null: validCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(newPassword)) {
            log.error(msg + "params is null: newPassword");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (StringTools.isPhone(account)) {
            smsValidCodeService.checkRepasswordValidCode(account, validCode, true);
        } else if (StringTools.isEmail(account)) {
            emailValidCodeService.checkRepasswordValidCode(account, validCode, true);
        } else {
            log.error(msg + "account format error, expect phone or email: {}", account);
            throw new ServiceException(UserErrorCode.PHONE_OR_EMAIL_IS_REQUIRED);
        }

        UserCoreBean user = findActivityUser(model);

        doUpdatePassword(model.getFactory(), model.getType(), user.getId(), newPassword);

    }

    @Override
    public void sendChangePhoneValidCode(String userId, String newPhone) throws ServiceException {
        String msg = "Failed to SendChangePhoneValidCode. ";
        if (VerifyTools.isBlank(userId)) {
            log.error(msg + "params is null: userId");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(newPhone)) {
            log.error(msg + "params is null: newPhone");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        // 检查手机号码格式
        if (VerifyTools.isBlank(!StringTools.isPhone(newPhone))) {
            log.error(msg + "params format error: newPhone=" + newPhone);
            throw new ServiceException(ResultCode.PARAMETER_FORMAT_ERROR);
        }

        UserCoreBean user = userCoreBasic.findById(userId);
        if (user == null) {
            log.error(msg + "user info not found: userId={}", userId);
            throw new ServiceException(UserErrorCode.USER_NOT_EXIST);
        }
        if (VerifyTools.isNotBlank(user.getPhone()) && user.getPhone().equals(newPhone)) {
            log.error(msg + "user phone not found, can't send sms: userId={}", userId);
            throw new ServiceException(UserErrorCode.PHONE_CHANGE_CAN_NOT_EQUALS_OLD);
        }

        // 检查手机号码是否已经注册
        AccountBean bean = new AccountBean(user.getTenantCode(), user.getUserType(), newPhone);
        userCoreExecutor.checkPhoneThrowOnAlreadyExists(bean, userId);

        // 发送短信验证码
        smsValidCodeService.sendChangePhoneValidCode(newPhone);
    }

    @Override
    public void checkChangePhoneValidCode(String userId, String newPhone, String validCode) throws ServiceException {
        String msg = "Failed to CheckChangePhoneValidCode. ";
        if (VerifyTools.isBlank(userId)) {
            log.error(msg + "params is null: userId");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(validCode)) {
            log.error(msg + "params is null: validCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        UserCoreBean user = userCoreBasic.findById(userId);
        if (user == null) {
            log.error(msg + "user info not found: userId={}", userId);
            throw new ServiceException(UserErrorCode.USER_NOT_EXIST);
        }

        // 检查短信验证码是否正确
        smsValidCodeService.checkChangePhoneValidCode(newPhone, validCode, false);
    }

    @Override
    public void changePhoneByValidCode(String userId, String newPhone, String validCode) throws ServiceException {
        String msg = "Failed to CheckChangePhoneValidCode. ";
        if (VerifyTools.isBlank(userId)) {
            log.error(msg + "params is null: userId");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(validCode)) {
            log.error(msg + "params is null: validCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(newPhone)) {
            log.error(msg + "params is null: newPhone");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        // 检查手机号码格式
        if (VerifyTools.isBlank(!StringTools.isPhone(newPhone))) {
            log.error("params format error: phone=" + newPhone);
            throw new ServiceException(ResultCode.PARAMETER_FORMAT_ERROR);
        }

        UserCoreBean user = userCoreBasic.findById(userId);
        if (user == null) {
            log.error(msg + "user info not found: userId={}", userId);
            throw new ServiceException(UserErrorCode.USER_NOT_EXIST);
        }

        if (VerifyTools.isNotBlank(user.getPhone()) && user.getPhone().equals(newPhone)) {
            log.error(msg + "user phone not found, can't send sms: userId={}", userId);
            throw new ServiceException(UserErrorCode.PHONE_CHANGE_CAN_NOT_EQUALS_OLD);
        }

        // 检查短信验证码是否正确
        smsValidCodeService.checkChangePhoneValidCode(newPhone, validCode, true);

        // 检查手机号码是否已经注册
        AccountBean bean = new AccountBean(user.getTenantCode(), user.getUserType(), newPhone);
        userCoreExecutor.checkPhoneThrowOnAlreadyExists(bean, userId);

        UserCoreWhere where = new UserCoreWhere();
        where.setId(user.getId());
        UserCoreUpdate update = new UserCoreUpdate();
        update.setWhere(where);
        update.setPhone(newPhone);
        userCoreBasic.update(update, true);
    }

    private void doUpdatePassword(String factory, IAccountType userType, String userId, String newPassword)
            throws ServiceException {

        // 密码加密
        String hashPassword = passwordService.create(userId, newPassword);
        UserCoreUpdate ud = new UserCoreUpdate();
        ud.setPassword(hashPassword);
        UserCoreWhere where = ud.getWhere(true);
        where.setTenantCode(factory);
        where.setUserType(userType);
        where.setId(userId);
        userCoreBasic.update(ud, true);
    }

}
